////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2012 Kentaro Sekimoto  All rights reserved.
////////////////////////////////////////////////////////////////////////////

#include <tinyhal.h>
#include "..\FM4.h"

///////////////////////////////////////////////////////////////////////////////
// FM4 clock configuration
//
// BSC_PSR_Val      0x00000000    // 0 = HCLK = Master Clock
// APBC0_PSR_Val    0x00000001    // 1 = PCLK0 = HCLK / 2
// APBC1_PSR_Val    0x00000081    // 1 = PCLK1 = HCLK / 2
// APBC2_PSR_Val    0x00000081    // 1 = PCLK2 = HCLK / 2
//
// PLL_CTL1_Val     0x00000001    // 1 = Division(PLLM) = 1/2
// PLL_CTL2_Val     0x00000023    // 36 = Division(PLLN) = 1/36
///////////////////////////////////////////////////////////////////////////////

#pragma arm section code = "SectionForBootstrapOperations"

/* IO initialization implemented in solution DeviceCode\Init */
void BootstrapCode_GPIO();

extern "C"
{
/*
 *  Stop HW Watchdog Timer
 */
static void HwwdtDisable(void)
{
    static uint32_t u32IoRegisterRead;

    /* UnLock (except WDG_CTL) */
    FM4_HWWDT->WDG_LCK = 0x1ACCE551;
    /* UnLock (WDG_CTL) */
    FM4_HWWDT->WDG_LCK = 0xE5331AAE;
    /* Disable WDG */
    FM4_HWWDT->WDG_CTL = 0x00;

    // Clock Setup
    FM4_CRG->BSC_PSR   = BSC_PSR_Val;               /* set System Clock presacaler */
    FM4_CRG->APBC0_PSR = APBC0_PSR_Val;             /* set APB0 presacaler */
    FM4_CRG->APBC1_PSR = APBC1_PSR_Val;             /* set APB1 presacaler */
    FM4_CRG->APBC2_PSR = APBC2_PSR_Val;             /* set APB2 presacaler */
    FM4_CRG->SWC_PSR   = SWC_PSR_Val | (1UL << 7);  /* set SW Watchdog presacaler */
    FM4_CRG->TTC_PSR   = TTC_PSR_Val;               /* set Trace Clock presacaler */

    FM4_CRG->CSW_TMR   = CSW_TMR_Val;               /* set oscillation stabilization wait time */

    if (SCM_CTL_Val & (1UL << 1)) {                 /* Main clock oscillator enabled ? */
        FM4_CRG->SCM_CTL |= (1UL << 1);             /* enable main oscillator */
        while (!(FM4_CRG->SCM_STR & (1UL << 1)));   /* wait for Main clock oscillation stable */
    }

    if (SCM_CTL_Val & (1UL << 3)) {                 /* Sub clock oscillator enabled ? */
        FM4_CRG->SCM_CTL |= (1UL << 3);             /* enable sub oscillator */
        while (!(FM4_CRG->SCM_STR & (1UL << 3)));   /* wait for Sub clock oscillation stable */
    }

    FM4_CRG->PSW_TMR   = PSW_TMR_Val;               /* set PLL stabilization wait time */
    FM4_CRG->PLL_CTL1  = PLL_CTL1_Val;              /* set PLLM and PLLK */
    FM4_CRG->PLL_CTL2  = PLL_CTL2_Val;              /* set PLLN          */

    if (SCM_CTL_Val & (1UL << 4)) {                 /* PLL enabled ? */
        FM4_CRG->SCM_CTL  |= (1UL << 4);            /* enable PLL */
        while (!(FM4_CRG->SCM_STR & (1UL << 4)));   /* wait for PLL stable */
    }

    FM4_CRG->SCM_CTL  |= (SCM_CTL_Val & 0xE0);      /* Set Master Clock switch */

    do {
        u32IoRegisterRead = (FM4_CRG->SCM_CTL & 0xE0);
    } while ((FM4_CRG->SCM_STR & 0xE0) != u32IoRegisterRead);
}

void __section(SectionForBootstrapOperations) FM4_BootstrapCode()
{
    HwwdtDisable();
}

void __section(SectionForBootstrapOperations) BootstrapCode()
{
    FM4_BootstrapCode();
    BootstrapCode_GPIO();
    PrepareImageRegions();
}
}
